/**
 * The Woosta True Fidelity Engine
 *
 * License... etc.
 **
 * Neural Networks
 *
 * An implementation of neural networks with back
 * propagation, parallelized using futures.
 **
 * Author: Sean Micklethwaite
 **/

#ifdef NOTDEFD

#include "neural_net.h"
#include "xml.h"
#include <string>
#include <map>

using namespace Rtl;


void InputNeuron::operator ()()
{
	mValue = (*mpSigmoid)(mThreshold, mInput);
};

void Neuron::operator ()()
{
	std::vector<Synapse>::const_iterator i;
	tScalar v = 0;

	//
	// Sum values at inputs
	//

	for(i = mInputs.begin(); i != mInputs.end(); i++){
		v += i->Weight * i->pInput->GetValue();
	};

	mValue = (*mpSigmoid)(mThreshold, v);
};

void NeuralNet::Evaluate(const tScalar *zInput, tScalar *zOutput)
{
	std::vector<InputNeuron*>::iterator	in;
	std::vector<Neuron*>::iterator		neu;

	//
	// Initialize inputs
	//

	for(in = mzpInputLayer.begin(); in != mzpInputLayer.end(); in++){
		(*in)->Create(zInput[(*in)->GetId()]);
	};

	//
	// Initialize other neurons
	//

	for(neu = mzpHiddenLayer.begin(); neu != mzpHiddenLayer.end(); neu++){
		(*neu)->Create();
	};
	for(neu = mzpOutputLayer.begin(); neu != mzpOutputLayer.end(); neu++){
		(*neu)->Create();
	};

	//
	// Get the output values, and we're done
	//

	for(neu = mzpOutputLayer.begin(); neu != mzpOutputLayer.end(); neu++){
		zOutput[(*neu)->GetId()] = (*neu)->GetValue();
	};
};

tScalar NeuralNet::_ThresholdFunc(tScalar t, tScalar v)
{
	return (v >= t ? 1.0 : 0);
};



/**
 * The parser: lets get ugly.
 **/
void NeuralNet::Load(tConstString sFile)
{
	/*
	xmlDocPtr		pDoc;
	xmlNodePtr		pNode, pLink;
	tString			s;
	tScalar			t, w;
	unsigned		id, iid;
	Neuron*			pNeuron;

	std::map<unsigned, InputNeuron*> inputs;
	std::map<unsigned, Neuron*> nodes;
	std::map<unsigned, Neuron*> outputs;
	std::map<unsigned, BaseNeuron*> linkables;
	std::map<unsigned, InputNeuron*>::const_iterator input;
	std::map<unsigned, Neuron*>::const_iterator node;

	//
	// Read the XML file
	//

	pDoc = xmlReadFile(sFile, NULL, NULL);
	if(!pDoc)
		throw "Failed to read XML file";

	if(xmlStrcmp(xmlDocGetRootElement(pDoc)->name, (xmlChar *)"NeuralNetwork") != 0)
		throw "Supplied file is not a neural network";

	// Parse it
	for(pNode = xmlDocGetRootElement(pDoc)->xmlChildrenNode;
		pNode != NULL; pNode = pNode->next)
	{
		if(xmlStrcmp(pNode->name, (xmlChar *)"Input") == 0){

			//
			// Input node
			//

			s = (tString)xmlGetProp(pNode, (const xmlChar *)"id");
			if(!s) throw "Parse error in NeuralNetwork - id tag not found";
			sscanf(s, "%lu", &id);

			s = (tString)xmlGetProp(pNode, (const xmlChar *)"t");
			if(!s){
				t = 0.5;
			}else{
				sscanf(s, "%lf", &t);
			};

			if(linkables[id] != NULL)
				throw "Error in NeuralNetwork - duplicate input ID";
			
			linkables[id] = inputs[id] = new InputNeuron(t, &_ThresholdFunc, id);

		}else if(xmlStrcmp(pNode->name, (xmlChar *)"Node") == 0){

			//
			// Hidden/output node
			//

			s = (tString)xmlGetProp(pNode, (const xmlChar *)"t");
			if(!s){
				t = 0.5;
			}else{
				sscanf(s, "%lf", &t);
			};

			if((s = (tString)xmlGetProp(pNode, (const xmlChar *)"id"))){
				
				//
				// Hidden node
				//

				sscanf(s, "%lu", &id);

				if(linkables[id] != NULL)
					throw "Error in NeuralNetwork - duplicate node ID";
			
				linkables[id] = pNeuron = nodes[id] = new Neuron(t, &_ThresholdFunc, id);

			}else if((s = (tString)xmlGetProp(pNode, (const xmlChar *)"oid"))){
				
				//
				// Output node
				//

				sscanf(s, "%lu", &id);

				if(outputs[id] != NULL)
					throw "Error in NeuralNetwork - duplicate output ID";
				
				pNeuron = outputs[id] = new Neuron(t, &_ThresholdFunc, id);
				
			}else throw "Parse error in NeuralNetwork - id tag not found";


			//
			// Parse the back links
			//

			for(pLink = pNode->xmlChildrenNode; pLink != NULL; pLink = pLink->next){
				if(xmlStrcmp(pLink->name, (xmlChar *)"Link") == 0){

					s = (tString)xmlGetProp(pLink, (const xmlChar *)"to");
					if(!s) throw "Parse error in NeuralNetwork - link to attribute not found";
					sscanf(s, "%lu", &iid);

					s = (tString)xmlGetProp(pLink, (const xmlChar *)"w");
					if(!s){
						w = 1;
					}else{
						sscanf(s, "%lf", &w);
					};

					if(linkables.find(iid) == linkables.end())
						throw "Error in neural network - link target not found";

					pNeuron->AddInput(linkables[iid], w);

				};
			}; // End parsing back links
		};
	}; // End parsing nodes#


	//
	// Now add the nodes to their relevant list
	//

	for(input = inputs.begin(); input != inputs.end(); input++){
		mzpInputLayer.push_back(input->second);
	};
	for(node = nodes.begin(); node != nodes.end(); node++){
		mzpHiddenLayer.push_back(node->second);
	};
	for(node = outputs.begin(); node != outputs.end(); node++){
		mzpOutputLayer.push_back(node->second);
	};

	xmlFreeDoc(pDoc);
	xmlCleanupParser();*/
};

#endif
